<?php

namespace App\Http\Requests;

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\Response;

class CommonRequest extends FormRequest
{

    public $scenes = [];
    public $currentScene;               //当前场景
    public $autoValidate = false;       //是否注入之后自动验证
    public $extendRules;

    public function authorize()
    {
        return true;
    }

    /**
     * 设置场景
     * @param $scene
     * @return $this
     */
    public function scene($scene)
    {
        $this->currentScene = $scene;

        return $this;
    }

    /**
     *使用扩展rule
     * @param string $name
     * @return $this
     */
    public function with($name = '')
    {
        if (is_array($name)) {
            $this->extendRules = array_merge(
                $this->extendRules[],
                array_map(
                    function ($v) {
                        return Str::camel($v);
                    },
                    $name
                )
            );
        } else {
            if (is_string($name)) {
                $this->extendRules[] = Str::camel($name);
            }
        }

        return $this;
    }

    /**
     *覆盖自动验证方法
     * @throws ValidationException
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function validateResolved()
    {
        if ($this->autoValidate) {
            $this->handleValidate();
        }
    }

    /**
     *验证方法
     * @param string $scene
     * @return array|void
     * @throws ValidationException
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function validate($scene = '')
    {
        if ($scene) {
            $this->currentScene = $scene;
        }
        $this->handleValidate();
    }

    /**
     * 根据场景获取规则
     * @return array|mixed
     */
    public function getRules()
    {
        $rules = $this->container->call([$this, 'rules']);
        $newRules = [];
        if ($this->extendRules) {
            $extendRules = array_reverse($this->extendRules);
            foreach ($extendRules as $extendRule) {
                if (method_exists($this, "{$extendRule}Rules")) {   //合并场景规则
                    $rules = array_merge(
                        $rules,
                        $this->container->call(
                            [$this, "{$extendRule}Rules"]
                        )
                    );
                }
            }
        }
        if ($this->currentScene && isset($this->scenes[$this->currentScene])) {
            $sceneFields = is_array($this->scenes[$this->currentScene]) ? $this->scenes[$this->currentScene] : explode(
                ',',
                $this->scenes[$this->currentScene]
            );
            foreach ($sceneFields as $field) {
                if (array_key_exists($field, $rules)) {
                    $newRules[$field] = $rules[$field];
                }
            }

            return $newRules;
        }

        return $rules;
    }

    /**
     *覆盖设置
     * @param $factory
     * @return mixed
     */
    public function validator($factory)
    {
        return $factory->make(
            $this->validationData(),
            $this->getRules(),
            $this->messages(),
            $this->attributes()
        );
    }

    /**
     * 最终验证方法
     * @throws \Illuminate\Auth\Access\AuthorizationException
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function handleValidate()
    {
        if (!$this->passesAuthorization()) {
            $this->failedAuthorization();
        }
        $instance = $this->getValidatorInstance();
        if ($instance->fails()) {
            $this->failedValidation($instance);
        }
    }

    /**
     *验证失败后
     * @param Validator $validator
     * @throws ValidationException
     */
    public function failedValidation(Validator $validator)
    {
        $errMessages = $validator->errors()->getMessages();
        foreach ($errMessages as $key => $errMsg) {
            // 调整格式
            if (isset($this->messages[$key])) {
                $msg = $this->messages[$key];
                if (!is_array($msg) || count($msg) < 2) {
                    continue;
                }
                throw new ValidationException($msg[1], Response::HTTP_UNPROCESSABLE_ENTITY);
            }
        }
        // 只提示第一个
        $errMsg = array_shift($errMessages);
        throw new \Exception($errMsg[0], Response::HTTP_UNPROCESSABLE_ENTITY);
    }


}
